/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "json_error.h"

using namespace json_error;

void json_error::HandleJsonError(napi_env env, size_t errorCode, size_t offset, const char *errorMsg,
                                 const std::unordered_map<size_t, const char*>& errorMessages)
{
    char errorCodeStr[JSON_ERROR_CODE_STR_LEN] = {'\0'};
    if (sprintf_s(errorCodeStr, JSON_ERROR_CODE_STR_LEN, "%d", errorCode + offset) == -1) {
        napi_throw_error(env, SPRINTF_S_ERROR_STR_SEPARATOR,
                         BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second);
    } else {
        auto messageIter = errorMessages.find(errorCode);
        if (messageIter != errorMessages.end()) {
            napi_throw_error(env, errorCodeStr, messageIter->second);
        } else {
            napi_throw_error(env, errorCodeStr, errorMsg);
        }
    }
}

void json_error::HandleBoundsCheckError(napi_env env, size_t errorCode, const char *errorMsg)
{
    char errorCodeStr[JSON_ERROR_CODE_STR_LEN] = {'\0'};
    if (sprintf_s(errorCodeStr, JSON_ERROR_CODE_STR_LEN, "%d", NAPI_ERROR_CODE_OFFSET + errorCode) == -1) {
        napi_throw_error(env, SPRINTF_S_ERROR_STR_SEPARATOR, BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second);
        return;
    }
    std::string fullMsg = std::string(BoundCheckErrorMessages.find(errorCode)->second) + std::string(errorMsg);
    napi_throw_error(env, errorCodeStr, fullMsg.c_str());
}

void json_error::JsonThrowHandle(napi_env env, JsonErrorCode errorCode, const char *jsonStr, size_t jsonStrLen,
                                 yyjson_read_err &err)
{
    char errorCodeStr[JSON_ERROR_CODE_STR_LEN] = {'\0'};
    if (sprintf_s(errorCodeStr, JSON_ERROR_CODE_STR_LEN, "%d", NAPI_ERROR_CODE_OFFSET + errorCode) == -1) {
        napi_throw_error(env, SPRINTF_S_ERROR_STR_SEPARATOR, BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second);
        return;
    }

    std::string str = err.msg;
    if ((jsonStr != nullptr) && (jsonStrLen != 0)) {
        size_t line = 0;
        size_t col = 0;
        size_t chr = 0;
        if (yyjson_locate_pos(jsonStr, jsonStrLen, err.pos, &line, &col, &chr)) {
            char lineColumnStr[LINE_COLUMN_INFO_LEN] = {'\0'};
            if (sprintf_s(lineColumnStr, LINE_COLUMN_INFO_LEN, "error at:(line:%lu, column:%lu)", line, col) == -1) {
                napi_throw_error(env, SPRINTF_S_ERROR_STR_SEPARATOR,
                                 BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second);
                return;
            }
            str += JSON_ERROR_STR_SEPARATOR;
            str += lineColumnStr;
        }
        if (err.pos < jsonStrLen) {
            char retainJsonStr[JSON_RETAIN_STR_INFO_LEN] = {'\0'};
            if (strncpy_s(retainJsonStr, JSON_RETAIN_STR_INFO_LEN, jsonStr + err.pos,
                          JSON_RETAIN_STR_INFO_LEN - 1) != EOK) {
                napi_throw_error(env, SPRINTF_S_ERROR_STR_SEPARATOR,
                                 BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second);
                return;
            }
            str += JSON_ERROR_STR_SEPARATOR;
            str += retainJsonStr;
        }
    }

    napi_throw_error(env, errorCodeStr, str.c_str());
}

void json_error::JsonThrowHandle(napi_env env, JsonErrorCode errorCode, const std::string &errorDescStr)
{
    char errorCodeStr[JSON_ERROR_CODE_STR_LEN] = {'\0'};
    if (sprintf_s(errorCodeStr, JSON_ERROR_CODE_STR_LEN, "%d", NAPI_ERROR_CODE_OFFSET + errorCode) == -1) {
        napi_throw_error(env, SPRINTF_S_ERROR_STR_SEPARATOR, BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second);
        return;
    }

    napi_throw_error(env, errorCodeStr, errorDescStr.c_str());
}

std::string json_error::GetErrorMsgByYYJSONReadErr(const char *jsonStr, size_t jsonStrLen,
                                                   yyjson_read_err &err)
{
    std::string str = (err).msg;
    if (((jsonStr) != nullptr) && ((jsonStrLen) != 0)) {
        size_t line = 0;
        size_t col = 0;
        size_t chr = 0;
        if (yyjson_locate_pos((jsonStr), (jsonStrLen), (err).pos, &line, &col, &chr)) {
            char lineColumnStr[JSON_RETAIN_STR_INFO_LEN] = {'\0'};
            if (sprintf_s(lineColumnStr, JSON_RETAIN_STR_INFO_LEN, ". Error at: (line:%lu, column:%lu). ",
                          line, col) == -1) {
                return BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second;
            }
            str += lineColumnStr;
        }
        if ((err).pos < (jsonStrLen)) {
            char retainJsonStr[JSON_RETAIN_STR_INFO_LEN] = {'\0'};
            if (strncpy_s(retainJsonStr, JSON_RETAIN_STR_INFO_LEN, (jsonStr) + (err).pos,
                          JSON_RETAIN_STR_INFO_LEN - 1) != EOK) {
                return BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second;
            }
            str += "First Error Character: ";
            str += retainJsonStr;
            str += ".";
        }
    }
    return str;
}

void json_error::HandleYYJSONReadError(napi_env env, int errorCode, const char* jsonStr, size_t jsonStrLen,
                                       yyjson_read_err& err)
{
    char errorCodeStr[JSON_ERROR_CODE_STR_LEN] = {'\0'};
    if (sprintf_s(errorCodeStr, JSON_ERROR_CODE_STR_LEN, "%d", YYJSON_ERROR_CODE_OFFSET + errorCode) == -1) {
        napi_throw_error(env, SPRINTF_S_ERROR_STR_SEPARATOR, BoundCheckErrorMessages.find(SPRINTF_S_ERROR)->second);
    } else {
        std::string errorMsg = GetErrorMsgByYYJSONReadErr(jsonStr, jsonStrLen, err);
        napi_throw_error(env, errorCodeStr, errorMsg.c_str());
    }
}